/*
 * JOGRE (Java Online Gaming Real-time Engine) - Server
 * Copyright (C) 2004  Bob Marks (marksie531@yahoo.com)
 * http://jogre.sourceforge.org
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package org.jogre.mayi.server;

import java.util.List;

import nanoxml.XMLElement;

import org.jogre.common.IGameOver;
import org.jogre.common.JogreModel;
import org.jogre.common.Player;
import org.jogre.common.Table;
import org.jogre.common.comm.CommGameOver;
import org.jogre.common.comm.CommNextPlayer;
import org.jogre.common.games.Deck;
import org.jogre.common.util.JogreLogger;
import org.jogre.mayi.common.CommMayIDiscard;
import org.jogre.mayi.common.CommMayIDrawCard;
import org.jogre.mayi.common.CommMayIHandScore;
import org.jogre.mayi.common.CommMayIMayI;
import org.jogre.mayi.common.CommMayIRequestDeal;
import org.jogre.mayi.common.CommMayIScorecard;
import org.jogre.mayi.common.MayIDeal;
import org.jogre.server.ServerConnectionThread;
import org.jogre.server.ServerController;

/**
 * Server table parser for spades. This server controller is slightly more
 * complex since it needs to keep track of all tables' deck of cards. By using a
 * hashtable, with the key being the table number, we are able to keep Deck
 * objects in server memory. This will also be useful for other card games. A
 * seperate variable named dealtHands keeps track of all the connected players
 * grabbing their hands from the server. When someone tries to grab a deck from
 * the server and all hands have already been grabbed, then a new deck is
 * shuffled and all variables are reset again.
 *
 * @author Garrett Lehman (Gman)
 * @version Alpha 0.2.3
 */
public class MayIServerController extends ServerController {

	// Logger to debug this class
	private JogreLogger logger = new JogreLogger(this.getClass());
	
	/**
	 * Constructor which takes a game key (read from directory).
	 *
	 * @param gameKey
	 *            gamekey (read from directory).
	 */
	public MayIServerController(String gameKey) {
		super(gameKey);
	}

	/**
     * Start game creates a new model.
     *
	 * @see org.jogre.server.ServerController#startGame(int)
	 */
	public void startGame (int tableNum) {
		
		int numPlayers = this.getTable(tableNum).getNumOfPlayers();
		
		setModel (tableNum, new MayIServerTableModel(numPlayers));
	}

	public void gameOver(ServerConnectionThread conn, int tableNum, int resultType) {
		// TODO Auto-generated method stub
	}

	/**
	 * Gets the server table model when a table number is specified
	 *
	 * @param tableNum
	 *            Table number
	 * @return the server table model associated to the table number provided
	 */
	public synchronized MayIServerTableModel getServerTableModel(int tableNum) {

		// Getting model from table so when tables get removed, so do the models.
		JogreModel model = this.getModel(tableNum);
		if (model == null) {
			model = new MayIServerTableModel(this.getTable(tableNum).getNumOfPlayers());
			this.setModel(tableNum, model);
		}
		return (MayIServerTableModel) model;

	}

	/**
	 * Parse a spades message and does all the spades server processing.
	 *
	 * @see org.jogre.server.ITableParser#parseTableMessage(org.jogre.server.ServerConnectionThread,
	 *      nanoxml.XMLElement)
	 */
	public void parseTableMessage(ServerConnectionThread conn,
			XMLElement message, int tableNum) {

		String messageType = message.getName();

		logger.info("parseTableMessage", "messageType: " + messageType);

		try
		{
			if (messageType.equals(CommMayIDrawCard.XML_NAME)) {
				drawCard(conn, new CommMayIDrawCard(message), tableNum);
			} else if (messageType.equals(CommMayIDiscard.XML_NAME)) {
				playCard(conn, new CommMayIDiscard(message), tableNum);
			} else if (messageType.equals(CommMayIRequestDeal.XML_NAME)) {
				requestDeal(conn, new CommMayIRequestDeal(message), tableNum);
			} else if (messageType.equals(CommMayIHandScore.XML_NAME)) {
				scoreHand(conn, new CommMayIHandScore(message), tableNum);
			} else if (messageType.equals(CommMayIMayI.XML_NAME)) {
				callMayI(conn, new CommMayIMayI(message), tableNum);
			} 
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
	}
	
	public void callMayI(ServerConnectionThread conn, CommMayIMayI mayi, int tableNum) {
		
		String turn = this.getTable(tableNum).getPlayerList().getCurrentPlayer().getUser().getUsername();
		
		conn.transmitToTablePlayer(turn, tableNum, mayi);
		
		/*
		MayIServerTableModel model = getServerTableModel(tableNum);
		
		if (model.getCurrentMayISeat() < 0) {
			model.setCurrentMayISeat(this.getSeatNum(score.getUsername(), tableNum));
		}
		else {
			int curr = this.getTable(tableNum).getPlayerList().getCurrentPlayer().getSeatNum();
			int req = this.getSeatNum(score.getUsername(), tableNum);
			int i = (curr + 1)%this.getTable(tableNum).getNumOfPlayers();
			while (i != curr) {
				if (i == model.getCurrentMayISeat()) {
					return;
				}
				else if (i == req) {
					
					return;
				}
			}
		}
		*/
	}
	
	public void scoreHand(ServerConnectionThread conn, CommMayIHandScore score, int tableNum) {
		MayIServerTableModel model = getServerTableModel(tableNum);
		model.addNewScore(score);
		
		if (model.allScoresReceived()) {
			CommMayIScorecard scorecard = new CommMayIScorecard(model.getNewScores());
			
			if ((model.getRound()+1) >= MayIConstants.ROUND_STRUCTURE.length) {
				String winner = model.getWinner();
				
				for (int i = 0; i < this.getTable(tableNum).getNumOfPlayers(); i++) {
					Player p = this.getTable(tableNum).getPlayerList().getPlayer(i);
					int status = -1;
					if (p.getUser().getUsername().equals(winner)) {
						status = IGameOver.WIN;
					}
					else {
						status = IGameOver.LOSE;
					}
					
					CommGameOver gameOver = new CommGameOver (status);
					scorecard.setGameOver(gameOver);
					
					conn.transmitToTablePlayer(p.getUser().getUsername(), tableNum, scorecard);
					model.clearNewScores();
				}
			}
			else {
				model.nextRound();
				conn.transmitToTablePlayers(tableNum, scorecard);
				
				this.getTable(tableNum).nextPlayer();
				CommNextPlayer nextPlayer = new CommNextPlayer(tableNum,
						this.getTable(tableNum).getPlayerList().getCurrentPlayerName());
				conn.transmitToTablePlayers(tableNum, nextPlayer);
			}
			
			
		}
	}
	
	public void drawCard(ServerConnectionThread conn, CommMayIDrawCard draw, int tableNum) {
		conn.transmitToTablePlayers(draw.getUsername(), tableNum, draw);
	}

	/**
	 * Play card from CommSpadesRequestHand object
	 *
	 * @param conn
	 *            Server connection thread
	 * @param playCard
	 *            Spades play card communication object
	 * @param tableNum
	 *            Table number
	 */
	public void playCard(ServerConnectionThread conn, CommMayIDiscard playCard, int tableNum) {

		// Get user who played the card
		String username = playCard.getUsername();

		// Trasnmit card to other players at table
		conn.transmitToTablePlayers(username, tableNum, playCard);
		
		if (!playCard.getOut()) {
			// If hand is not over, get next player from table
			Table table = conn.getTableList().getTable(tableNum);
			table.nextPlayer();
			CommNextPlayer nextPlayer = new CommNextPlayer(tableNum,
					table.getPlayerList().getCurrentPlayerName());
			conn.transmitToTablePlayers(tableNum, nextPlayer);
		}

		
	}
	
	public void requestDeal(ServerConnectionThread conn, CommMayIRequestDeal requestDeck, int tableNum) {
				
		MayIServerTableModel model = getServerTableModel(tableNum);
		String username = requestDeck.getUsername();
		int seatNum = this.getSeatNum(username, tableNum);
		
		
		Deck deck = model.requestDeck();
		List<Deck> hands = model.getHandsOrderedBySeat(seatNum);
		MayIDeal deal = new MayIDeal(deck, hands);
		
		conn.transmitToTablePlayer(username, tableNum, deal);
	}

}